#region Copyright and Licensing Notice
// Copyright (C) 2011 Steven Bosnick
// 
// This program is open source software; you can redistribute it 
// and/or modifiy it under the terms of the Eclipse Public License,
// version 1.0.
// 
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A 
// PARTICULAR PURPOSE. See the Eclipse Public License for more
// details.
// 
// You should have received a copy of the Eclipse Public License 
// along with this program; if not, you can find a copy at
// "http://www.opensource.org/licenses/eclipse-1.0.php".
#endregion
using System;
using BitwiseOre.SharedMemory.Core;
using BitwiseOre.SharedMemory.Core.Common;
using BitwiseOre.SharedMemory.Core.Primatives;
using NUnit.Framework;

namespace BitwiseOre.Tests.SharedMemory.Primatives
{
    [TestFixture]
    public sealed class IndexQueueFixture : AssertionHelper
    {
        [Test(Description = "Checkes that dequeing an empty queue returns NullIndex")]
        public void Dequeue_Empty()
        {
            var queue = new IndexQueue(new TestLayout(), new TestIntArray());
            ((ISharedObjectInit)queue).InitializeNew();

            var result = queue.Dequeue();

            Expect(result, EqualTo(QueueConstants.NullIndex),
                "Unexpected result returned from Dequeue.");
        }

        [Test(Description = "Checks that dequeing after enqueing returns the enqueued value")]
        public void Dequeue_AfterEnqueue()
        {
            const int expectedvalue = 3;
            var queue = new IndexQueue(new TestLayout(), new TestIntArray());
            ((ISharedObjectInit)queue).InitializeNew();
            queue.Enqueue(expectedvalue);

            var result = queue.Dequeue();
            
            Expect(result, EqualTo(expectedvalue));
        }

        [Test(Description = "Check that dequeueing twice after two enqueues returns the second value queued")]
        public void Dequeue_TwiceAfterDoubleEnqueue()
        {
            var values = new[] {2, 3};
            var queue = new IndexQueue(new TestLayout(), new TestIntArray());
            ((ISharedObjectInit)queue).InitializeNew();
            foreach (var value in values)
            {
                queue.Enqueue(value);
            }

            queue.Dequeue();
            var result = queue.Dequeue();

            Expect(result, EqualTo(values[1]));
        }


        private sealed class TestLayout : IIndexQueueLayout
        {
            public CountedIndex Head { get; set; }
            public CountedIndex Tail { get; set; }
            public int Dummy { get; set; }
            public bool CasHead(CountedIndex comparand, CountedIndex value)
            {
                if (Head == comparand)
                {
                    Head = value;
                    return true;
                }
                return false;
            }

            public bool CasTail(CountedIndex comparand, CountedIndex value)
            {
                if (Tail == comparand)
                {
                    Tail = value;
                    return true;
                }
                return false;
            }

            public bool CasDummy(int comarand, int value)
            {
                if (Dummy == comarand)
                {
                    Dummy = value;
                    return true;
                }
                return false;
            }
        }
        private sealed class TestIntArray : IIntArray
        {
            private readonly int[] _array = new int[5];

            public int this[int index]
            {
                get { return _array[index]; }
                set { _array[index] = value; }
            }

            public int Capacity
            {
                get { return 5 * sizeof(int); }
            }

            public int Count
            {
                get { throw new NotImplementedException(); }
            }

            public bool InterlockedCompareExchange(int index, int comparand, int value)
            {
                if (_array[index] == comparand)
                {
                    _array[index] = value;
                    return true;
                }
                return false;
            }
        }
    }

}